/// File: VSLabFSICore\configuration.fs
/// 
/// Author: Antonio Cisternino (cisterni@di.unipi.it)
///   
/// ------------------------------------------------------------
/// Copyright (c) Microsoft Corporation.  All rights reserved.
/// 
/// The use and distribution terms for this software are 
/// contained in the file named license.txt, which can be found 
/// in the root of this distribution.
/// By using this software in any fashion, you are agreeing to 
/// be bound by the terms of this license.
///
/// You must not remove this notice, or any other, from this
/// software.
/// ------------------------------------------------------------

module VSLab.Configuration

open System.Windows.Forms
open VSLab.Packages

/// <summary>
/// Represent the VSLab configuration. This class is conceived not as
/// a singleton. You may create (and implicitly load) the configuration
/// and discard it if needed. This may be a problem if multiple configurations
/// are created at the same time.
/// </summary>
type internal VSLabConfiguration() =
  let mutable pkgs = ReadPackageConfiguration()
  
  /// <summary>
  /// Save the configuration.
  /// </summary>
  member x.Save() =
    WritePackageConfiguration(pkgs)

  /// <summary>
  /// Reload package configuration.
  /// </summary>
  member x.ReloadPackages() =
    pkgs <- ReadPackageConfiguration()

  /// <summary>
  /// Return the list of packages and their configuration properties.
  /// </summary>
  member x.Packages
    with get() = pkgs

/// <summary>
/// Creates an instance of the Package configuration tab panel
/// to be used from the configuration panel.
/// </summary>
/// <param name="conf">The configuration of VSLab</param>
let internal PackageConfigurationPanel(conf:VSLabConfiguration) =
  // Binding source
  let src = new BindingSource()
  src.DataSource <- typeof<PackageState>

  // Columns
  let startupCol = new DataGridViewCheckBoxColumn(DataPropertyName="LoadOnStartup", HeaderText="Startup", SortMode = DataGridViewColumnSortMode.NotSortable)
  let opennsCol = new DataGridViewCheckBoxColumn(DataPropertyName="OpenNS", HeaderText="Auto open namespace", ToolTipText="Open automatically Package namespaces", SortMode = DataGridViewColumnSortMode.NotSortable)
  let globalCol = new DataGridViewCheckBoxColumn(DataPropertyName="IsGlobalPackage", HeaderText="Global", SortMode = DataGridViewColumnSortMode.NotSortable, ReadOnly=true)
  let pkgnameCol = new DataGridViewTextBoxColumn(DataPropertyName="PackageName", HeaderText="Name", ReadOnly=true, SortMode = DataGridViewColumnSortMode.NotSortable)
  let pkgdescCol = new DataGridViewTextBoxColumn(DataPropertyName="PackageDescription", HeaderText="Description", ReadOnly=true, SortMode = DataGridViewColumnSortMode.NotSortable)
  let loadCol = new DataGridViewLinkColumn(DataPropertyName="PackageLoaded", HeaderText="", SortMode = DataGridViewColumnSortMode.NotSortable)

  // Data grid
  let dg = 
    new DataGridView(
      AllowUserToAddRows=false,
      AllowUserToDeleteRows=false,
      AutoGenerateColumns=false,
      ColumnHeadersHeightSizeMode=DataGridViewColumnHeadersHeightSizeMode.AutoSize,
      Dock=DockStyle.Fill,
      RowHeadersVisible=false)

  let dgc (c:#DataGridViewColumn) = c :> DataGridViewColumn

  dg.Columns.AddRange([| (dgc startupCol); (dgc opennsCol); (dgc globalCol); (dgc pkgnameCol); (dgc pkgdescCol); (dgc loadCol) |])

  dg.CellContentClick.Add(fun e -> ())

  dg.DataSource <- (conf.Packages :> obj)

  dg.BackColor <- System.Drawing.SystemColors.Window
  
  dg.CellContentClick.Add(fun ev ->
    let pk = conf.Packages.[ev.RowIndex]
    if ev.ColumnIndex = 5 then
      Load(pk.PackageLocation)
      conf.ReloadPackages()    
      dg.DataSource <- (conf.Packages :> obj)
  )

  let p = new Panel(Dock=DockStyle.Top)
  let b = new Button(Text="Install global package...", Anchor=(AnchorStyles.Right ||| AnchorStyles.Top), Top=10, Width=150,Left=(p.Width - 160))
  let lb = new Button(Text="Install user package...", Anchor=(AnchorStyles.Right ||| AnchorStyles.Top),Top=(10 + b.Height),Width=150,Left=(p.Width - 160))
  let l = new Label(Anchor=(AnchorStyles.Top ||| AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom),Left=10,Width=(p.Width - 180),Top=10,Height=(p.Height - 20))
  l.Text <- @"Packages are assemblies managed by VSLab to quickly support loading of Viewlets and functions, packages can be installed in the user profile or in a folder available to all users";

  p.Controls.Add(l)
  p.Controls.Add(b)
  p.Controls.Add(lb)
  
  p.Height <- b.Height * 2 + 30
  
  b.Click.Add(fun _ ->
    let ifd = new OpenFileDialog()
    ifd.Title <- "Install global package"
    ifd.Filter <- "VSLab package (*.dll)|*.dll" 
    ifd.Multiselect <- true
    match ifd.ShowDialog(p) with
    | DialogResult.OK ->
      for f in ifd.FileNames do
        if not (InstallGlobalPackage (f) false) then
          MessageBox.Show(p, "Error installing package:\n\n" + f, "Package installation error", MessageBoxButtons.OK, MessageBoxIcon.Error) |> ignore
      conf.ReloadPackages()
      dg.DataSource <- (conf.Packages :> obj)
    | _ -> ()
  )

  lb.Click.Add(fun _ ->
    let ifd = new OpenFileDialog()
    ifd.Title <- "Install user package"
    ifd.Filter <- "VSLab package (*.dll)|*.dll" 
    ifd.Multiselect <- true
    match ifd.ShowDialog(p) with
    | DialogResult.OK ->
      for f in ifd.FileNames do
        if not (InstallUserPackage (f) false) then
          MessageBox.Show(p, "Error installing package:\n\n" + f, "Package installation error", MessageBoxButtons.OK, MessageBoxIcon.Error) |> ignore
      conf.ReloadPackages()
      dg.DataSource <- (conf.Packages :> obj)
    | _ -> ()
  )

  let pkgtab = new TabPage("Packages")

  pkgtab.Controls.Add(dg)
  pkgtab.Controls.Add(p)
  
  pkgtab

/// <summary>
/// Shows the VSLab configuration dialog.
/// </summary>
let VSLabConfigurationDialog() = 
  let f = new Form(Text="VSLab Configuration", TopMost=true, Width=640, Height=480)
  let conf = new VSLabConfiguration()
  let tabs = new TabControl(Dock=DockStyle.Fill)

  tabs.Controls.Add(PackageConfigurationPanel(conf))
  f.Controls.Add(tabs)

  let p = new FlowLayoutPanel(FlowDirection=FlowDirection.RightToLeft, Dock=DockStyle.Bottom, Margin=new Padding(0), Padding=new Padding(0))
  let s = new Button(Text="Save", Margin=new Padding(0), Padding=new Padding(0))
  let c = new Button(Text="Cancel", Margin=new Padding(0), Padding=new Padding(0))
  
  s.Click.Add(fun _ -> f.DialogResult <- DialogResult.OK)
  c.Click.Add(fun _ -> f.DialogResult <- DialogResult.Cancel)

  p.Height <- c.PreferredSize.Height

  p.Controls.Add(c)
  p.Controls.Add(s)
  
  f.Controls.Add(p)
  f.ShowInTaskbar <- false
  f.MaximizeBox <- false
  f.MinimizeBox <- false

  f.FormBorderStyle <- FormBorderStyle.FixedDialog

  match f.ShowDialog() with
  | DialogResult.OK -> conf.Save()
  | _ -> ()
